package com.zijidelu.luframework.starter.scanner;

import java.util.*;

/**
 * 单依赖扫描器排序器
 * <p>
 * 该工具类用于根据扫描器之间的单依赖关系，计算出正确的执行顺序。
 * 它确保被依赖的扫描器总是先于依赖它的扫描器执行。
 * 同时，它能精确地检测并报告循环依赖和缺失依赖的错误。
 *
 * @author zijidelu
 */
public class SingleDependencyScannerSorter {

    /**
     * 对所有扫描器按依赖关系进行排序。
     *
     * @param scannerBeans Spring容器中所有扫描器实例的Map
     * @return 按正确执行顺序排列的扫描器列表
     * @throws IllegalStateException 如果检测到循环依赖或某个扫描器依赖的扫描器不存在
     */
    public static List<AbstractAutoScanner> sort(Map<String, Object> scannerBeans) {
        // 1. 准备阶段：构建一个从Class到Scanner实例的快速查找索引
        Map<Class<? extends AbstractAutoScanner>, AbstractAutoScanner> scannerIndex = buildScannerIndex(scannerBeans);

        List<AbstractAutoScanner> sortedScanners = new ArrayList<>();
        Set<AbstractAutoScanner> processedScanners = new HashSet<>();

        // 2. 处理阶段：遍历每个扫描器，解析其完整的依赖链
        for (AbstractAutoScanner scanner : scannerIndex.values()) {
            if (processedScanners.contains(scanner)) {
                continue; // 如果已经处理过，则跳过
            }

            // 解析当前扫描器及其所有上游依赖
            DependencyChainResolution resolution = resolveDependencyChain(scanner, scannerIndex);

            // 3. 结果处理：根据解析结果，要么合并到排序列表，要么抛出异常
            if (resolution.success()) {
                addResolvedChainToSortedList(resolution.resolvedChain(), sortedScanners, processedScanners);
            } else {
                throw new IllegalStateException(resolution.errorMessage());
            }
        }

        return sortedScanners;
    }

    /**
     * 构建一个从Class到Scanner实例的快速查找索引，提高后续查找效率。
     */
    private static Map<Class<? extends AbstractAutoScanner>, AbstractAutoScanner> buildScannerIndex(Map<String, Object> scannerBeans) {
        Map<Class<? extends AbstractAutoScanner>, AbstractAutoScanner> index = new HashMap<>();
        for (Object bean : scannerBeans.values()) {
            if (bean instanceof AbstractAutoScanner scanner) {
                index.put(scanner.getClass(), scanner);
            }
        }
        return index;
    }

    /**
     * 解析一个扫描器的完整依赖链，直到没有依赖为止。
     * <p>
     * 在此过程中，它会检测循环依赖和缺失依赖，并将结果封装在 {@link DependencyChainResolution} 中返回。
     *
     * @param startScanner 起始扫描器
     * @param scannerIndex 扫描器实例索引
     * @return 包含解析结果的对象
     */
    private static DependencyChainResolution resolveDependencyChain(AbstractAutoScanner startScanner,
                                                                    Map<Class<? extends AbstractAutoScanner>, AbstractAutoScanner> scannerIndex) {
        // path 记录了当前的依赖链，例如 [A, B, C] 表示 A -> B -> C
        List<AbstractAutoScanner> path = new ArrayList<>();
        // visitingSet 用于快速判断当前是否在追溯路径中，是检测循环依赖的关键
        Set<AbstractAutoScanner> visitingSet = new HashSet<>();

        AbstractAutoScanner current = startScanner;

        // 沿着依赖链一直向下追溯
        while (current != null) {
            // 检查循环依赖：如果当前节点已在追溯路径中，说明找到了环路
            if (visitingSet.contains(current)) {
                String cyclePath = buildCyclePathString(path, current);
                return DependencyChainResolution.failure(String.format("检测到循环依赖！路径为: %s", cyclePath));
            }

            visitingSet.add(current);
            path.add(current);

            // 获取下一个依赖的扫描器
            Class<? extends AbstractAutoScanner> depClass = current.dependOn();
            if (depClass == null) {
                break; // 链条到达终点（没有依赖）
            }

            current = scannerIndex.get(depClass);
            if (current == null) {
                // 检查缺失依赖：如果依赖的扫描器在索引中找不到
                String scannerName = path.get(path.size() - 1).getClass().getName();
                return DependencyChainResolution.failure(
                        String.format("扫描器 '%s' 依赖的 '%s' 未找到！", scannerName, depClass.getName())
                );
            }
        }

        return DependencyChainResolution.success(path);
    }

    /**
     * 将解析成功的依赖链，按正确顺序（被依赖者在前）添加到最终排序列表中。
     *
     * @param resolvedPath      解析出的依赖链（例如 [A, B, C]）
     * @param sortedScanners    最终的排序列表
     * @param processedScanners 已处理的扫描器集合
     */
    private static void addResolvedChainToSortedList(List<AbstractAutoScanner> resolvedPath,
                                                     List<AbstractAutoScanner> sortedScanners,
                                                     Set<AbstractAutoScanner> processedScanners) {
        // resolvedPath 是 [A, B, C] (A依赖B，B依赖C)，执行顺序必须是 C, B, A
        // 因此从后往前遍历并添加
        for (int i = resolvedPath.size() - 1; i >= 0; i--) {
            AbstractAutoScanner scanner = resolvedPath.get(i);
            if (!processedScanners.contains(scanner)) {
                sortedScanners.add(scanner);
                processedScanners.add(scanner);
            }
        }
    }

    /**
     * 根据检测到的循环，构建一个可读的循环路径字符串。
     */
    private static String buildCyclePathString(List<AbstractAutoScanner> path, AbstractAutoScanner currentScanner) {
        StringBuilder cyclePath = new StringBuilder();
        int startIndex = path.indexOf(currentScanner);
        // 从循环起点开始拼接路径
        for (int i = startIndex; i < path.size(); i++) {
            cyclePath.append(path.get(i).getClass().getSimpleName()).append(" -> ");
        }
        // 补上形成循环的最后一个节点
        cyclePath.append(currentScanner.getClass().getSimpleName());
        return cyclePath.toString();
    }

    /**
     * 内部结果类，用于封装依赖链解析的结果。
     * <p>
     * 使用这种模式可以使方法职责更单一，逻辑更清晰。
     */
    private record DependencyChainResolution(boolean success, List<AbstractAutoScanner> resolvedChain,
                                             String errorMessage) {

        public static DependencyChainResolution success(List<AbstractAutoScanner> chain) {
            return new DependencyChainResolution(true, chain, null);
        }

        public static DependencyChainResolution failure(String errorMessage) {
            return new DependencyChainResolution(false, null, errorMessage);
        }
    }
}
